﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using MiscUtil;
using TlvLib;

namespace LprConfiger.Winform
{
    class PacketHandler
    {
        private TlvUnpacker _unpacker;

        private const short PacktypeQueryConfig = 1020;
        private const short PacktypeSetupConfig = 1021;

        private const byte ConfigItemCommon = 0x01;
        private const byte ConfigItemPolice = 0x02;
        private const byte ConfigItemGateway = 0x03;

        public event EventHandler<EventArgs<CFGCommon>> CommonConfigReceived;
        public event EventHandler<EventArgs<CFGPolice>> PoliceConfigReceived;

        public void OnPoliceConfigReceived(EventArgs<CFGPolice> e)
        {
            EventHandler<EventArgs<CFGPolice>> handler = PoliceConfigReceived;
            if (handler != null) handler(this, e);
        }

        public void OnCommonConfigReceived(EventArgs<CFGCommon> e)
        {
            EventHandler<EventArgs<CFGCommon>> handler = CommonConfigReceived;
            if (handler != null) handler(this, e);
        }

        public PacketHandler(string host, int port)
        {
            _unpacker = new TlvUnpacker(host, port);
            _unpacker.RawPacketReceived += UnpadkerOnRawPacketReceived;
            _unpacker.StatusReport += OnUnpackerOnStatusReport;
            _unpacker.Start();

        }

        public void Close()
        {
            if (_unpacker != null)
            {
                _unpacker.Stop();
            }
        }

        private void OnUnpackerOnStatusReport(object sender, EventArgs<ConnectionStatus> args)
        {
            if (args.Value.Status == Status.Success)
            {
                RequestConfig();
            }
        }

        public void RequestConfig()
        {
            var packet = new RawPacket() 
                        {IsRequest = true, MessageId = PacktypeQueryConfig, Payload = new[]{ConfigItemCommon} };
            _unpacker.Send(packet);
            packet = new RawPacket()
                         {IsRequest = true, MessageId = PacktypeQueryConfig, Payload = new[] {ConfigItemPolice}};
            _unpacker.Send(packet);
        }

        private void UnpadkerOnRawPacketReceived(object sender, RawPacketReceivedEventArgs args)
        {
            if (args.Value.MessageId == PacktypeQueryConfig)
            {
                var payload = args.Value.Payload;
                var configItem = payload[0];
                switch (configItem)
                {
                    case ConfigItemCommon:
                        {
                            var cfgCommon = ReadCfgCommonPacket(payload);
                            var a = new EventArgs<CFGCommon>(cfgCommon);
                            OnCommonConfigReceived(a);
                        }
                        break;
                    case ConfigItemGateway:
                        break;
                    case ConfigItemPolice:
                        {
                            var cfgPolice = ReadCfgPolice(payload);
                            var provience = Encoding.UTF8.GetString(cfgPolice.reco.province, 0, 3);
                            var a = new EventArgs<CFGPolice>(cfgPolice);
                            OnPoliceConfigReceived(a);
                        }
                        break;
                }

            }
        }

        private CFGPolice ReadCfgPolice(byte[] payload)
        {
            var cfgPolice = ReadPacket<CFGPolice>(payload);
            cfgPolice = EndianConverter.FromBigEndian(ref cfgPolice);
            return cfgPolice;
        }

        private CFGCommon ReadCfgCommonPacket(byte[] payload)
        {
            var configCommon = ReadPacket<CFGCommon>(payload);
            configCommon = EndianConverter.FromBigEndian(ref configCommon);
            return configCommon;
        }

        private static T ReadPacket<T> (byte[] payload)
        {
            const int idx = 1;
            var structLen = Marshal.SizeOf(typeof (T));
            var ptr = Marshal.AllocHGlobal(structLen);
            Marshal.Copy(payload, idx, ptr, structLen);
            var packet = (T) Marshal.PtrToStructure(ptr, typeof (T));
            Marshal.FreeHGlobal(ptr);
            return packet;
        }
    }
}
